#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
任务管理模块

负责管理任务队列、跟踪任务状态和提供任务统计信息
"""

import threading
import time
from enum import Enum
from typing import Dict, List, Any, Optional


class TaskStatus(Enum):
    """
    任务状态枚举
    """
    PENDING = "pending"    # 任务等待执行
    RUNNING = "running"    # 任务正在执行
    SUCCESS = "success"    # 任务执行成功
    FAILED = "failed"      # 任务执行失败
    RETRYING = "retrying"  # 任务正在重试
    CANCELLED = "cancelled"  # 任务被取消


class Task:
    """
    任务类
    
    表示一个数据库表同步任务，包含任务的相关信息和状态
    """
    
    def __init__(self, task_id: str, task_func: callable, *args, **kwargs):
        """
        初始化任务
        
        Args:
            task_id: 任务ID（通常是表名）
            task_func: 要执行的任务函数
            *args: 传递给任务函数的位置参数
            **kwargs: 传递给任务函数的关键字参数
        """
        self.task_id = task_id
        self.task_func = task_func
        self.args = args
        self.kwargs = kwargs
        self.status = TaskStatus.PENDING
        self.created_at = time.time()
        self.started_at = None
        self.completed_at = None
        self.duration = None
        self.result = None
        self.error = None
        self.retry_count = 0
        self.thread_id = None
        self.thread_name = None
    
    def start(self):
        """
        开始执行任务，更新任务状态
        """
        self.status = TaskStatus.RUNNING
        self.started_at = time.time()
        self.thread_id = threading.get_ident()
        self.thread_name = threading.current_thread().name
    
    def retry(self):
        """
        重试任务，更新任务状态
        """
        self.status = TaskStatus.RETRYING
        self.retry_count += 1
    
    def complete(self, success: bool, result=None, error=None):
        """
        完成任务，更新任务状态和结果
        
        Args:
            success: 任务是否成功
            result: 任务执行结果（成功时）
            error: 错误信息（失败时）
        """
        self.status = TaskStatus.SUCCESS if success else TaskStatus.FAILED
        self.completed_at = time.time()
        self.result = result
        self.error = error
        
        # 计算任务耗时
        if self.started_at:
            self.duration = self.completed_at - self.started_at
    
    def cancel(self):
        """
        取消任务
        """
        if self.status in (TaskStatus.PENDING, TaskStatus.RETRYING):
            self.status = TaskStatus.CANCELLED
            self.completed_at = time.time()
            return True
        return False
    
    def to_dict(self) -> Dict[str, Any]:
        """
        将任务信息转换为字典格式
        
        Returns:
            Dict[str, Any]: 任务信息字典
        """
        return {
            'task_id': self.task_id,
            'status': self.status.value,
            'created_at': self.created_at,
            'started_at': self.started_at,
            'completed_at': self.completed_at,
            'duration': self.duration,
            'result': self.result,
            'error': self.error,
            'retry_count': self.retry_count,
            'thread_id': self.thread_id,
            'thread_name': self.thread_name
        }


class TaskManager:
    """
    任务管理器类
    
    负责管理所有任务，提供任务添加、查询、状态更新等功能
    确保在多线程环境下的线程安全
    """
    
    def __init__(self):
        """
        初始化任务管理器
        """
        # 任务字典，key为task_id，value为Task对象
        self.tasks = {}
        # 用于保证线程安全的锁
        self._lock = threading.RLock()
        # 任务状态统计
        self._stats = {
            'total': 0,
            'pending': 0,
            'running': 0,
            'success': 0,
            'failed': 0,
            'cancelled': 0
        }
    
    def add_task(self, task_id: str, task_func: callable, *args, **kwargs) -> Task:
        """
        添加新任务
        
        Args:
            task_id: 任务ID
            task_func: 任务函数
            *args: 任务函数参数
            **kwargs: 任务函数关键字参数
            
        Returns:
            Task: 创建的任务对象
            
        Raises:
            ValueError: 如果任务ID已存在
        """
        with self._lock:
            if task_id in self.tasks:
                raise ValueError(f"任务ID '{task_id}' 已存在")
            
            task = Task(task_id, task_func, *args, **kwargs)
            self.tasks[task_id] = task
            self._update_stats('pending', 1)
            
            return task
    
    def get_task(self, task_id: str) -> Optional[Task]:
        """
        获取指定ID的任务
        
        Args:
            task_id: 任务ID
            
        Returns:
            Task: 任务对象，如果不存在则返回None
        """
        with self._lock:
            return self.tasks.get(task_id)
    
    def update_task_status(self, task_id: str, status: TaskStatus, **kwargs) -> bool:
        """
        更新任务状态
        
        Args:
            task_id: 任务ID
            status: 新状态
            **kwargs: 其他要更新的属性
            
        Returns:
            bool: 更新是否成功
        """
        with self._lock:
            task = self.tasks.get(task_id)
            if not task:
                return False
            
            # 更新统计信息
            old_status = task.status
            self._update_stats(old_status.value, -1)
            self._update_stats(status.value, 1)
            
            # 更新任务状态
            task.status = status
            
            # 更新其他属性
            for key, value in kwargs.items():
                if hasattr(task, key):
                    setattr(task, key, value)
            
            return True
    
    def _update_stats(self, status: str, delta: int):
        """
        更新统计信息
        
        Args:
            status: 要更新的状态
            delta: 变化量
        """
        if status in self._stats:
            self._stats[status] += delta
        self._stats['total'] += delta
    
    def get_stats(self) -> Dict[str, int]:
        """
        获取任务统计信息
        
        Returns:
            Dict[str, int]: 统计信息字典
        """
        with self._lock:
            # 返回统计信息的副本，避免外部修改
            return self._stats.copy()
    
    def get_tasks_by_status(self, status: TaskStatus) -> List[Task]:
        """
        获取指定状态的所有任务
        
        Args:
            status: 要查询的状态
            
        Returns:
            List[Task]: 任务列表
        """
        with self._lock:
            return [task for task in self.tasks.values() if task.status == status]
    
    def cancel_all_pending_tasks(self) -> int:
        """
        取消所有未执行的任务
        
        Returns:
            int: 成功取消的任务数量
        """
        with self._lock:
            cancelled_count = 0
            for task in self.tasks.values():
                if task.cancel():
                    cancelled_count += 1
                    self._update_stats('pending', -1)
                    self._update_stats('cancelled', 1)
            return cancelled_count
    
    def get_all_tasks(self) -> Dict[str, Task]:
        """
        获取所有任务
        
        Returns:
            Dict[str, Task]: 所有任务的字典副本
        """
        with self._lock:
            return self.tasks.copy()
    
    def get_task_progress(self) -> float:
        """
        获取任务完成进度
        
        Returns:
            float: 完成进度百分比 (0.0 到 100.0)
        """
        with self._lock:
            total = self._stats['total']
            if total == 0:
                return 0.0
            completed = self._stats['success'] + self._stats['failed'] + self._stats['cancelled']
            return (completed / total) * 100.0